import axios, { type InternalAxiosRequestConfig } from 'axios'
import { message, Modal } from 'ant-design-vue'
import { useUserInfoStore } from '@/stores/modules/userInfo'

import { useCommonStore } from '@/stores/modules/common'
import md5 from 'md5'
import { apiChangeUserTeam, apiUserTeamList } from '@/api/user'
import { useMenuStore } from '@/stores/modules/menu'
import { useChatBus } from '@/hook/useChatBus'
// 创建axios实例
export const request = axios.create({
  baseURL: import.meta.env.VITE_APP_URL, // api的base_url
  timeout: 60000 // 请求超时时间
})

const whiteList = ['/chat/copilotApply/insert'] //拦截白名单 页面单独做异常处理
const requestUniquekey = 'r-token'

const pendingMap = new Map() //请求池，存储请求

/**
 * 生成每个请求唯一的键
 * @param {*} config
 * @returns string
 */
function getPendingKey(config: any) {
  const { url, method, params } = config
  const { data } = config
  // if (typeof data === 'string') data = parse(data) // response里面返回的config.data是个字符串对象
  return md5([url, method, JSON.stringify({ ...params, ...data })].join(''))
}

export const NO_LOADING_KEY = 'no-loading'

// 忽略业务错误
export const IGNORE_BUSINESS_ERROR = 'IGNORE_BUSINESS_ERROR'

//添加信息到请求池中
const addPending = (config: InternalAxiosRequestConfig<any>) => {
  const pendingKey = getPendingKey(config)
  config.cancelToken =
    config.cancelToken ||
    new axios.CancelToken((cancel) => {
      //axios 取消请求（axios中取消请求情况分为1：取消该请求之后的相同请求；2：取消该请求之前的相同请求）
      if (config.headers[NO_LOADING_KEY]) return
      if (pendingMap.has(pendingKey)) {
        return
      }
      pendingMap.set(pendingKey, cancel)
      const commonStore = useCommonStore()
      commonStore.setCurRequestNum(pendingMap.size) //记录请求池中请求的数量
    })
  return pendingKey
}

const removePending = (config: InternalAxiosRequestConfig<any>) => {
  const pendingKey = config.headers[requestUniquekey] ?? getPendingKey(config)
  if (pendingMap.has(pendingKey)) {
    const cancelToken = pendingMap.get(pendingKey)
    cancelToken(pendingKey) //如果请求过则取消请求
    pendingMap.delete(pendingKey)
    const commonStore = useCommonStore()
    commonStore.setCurRequestNum(pendingMap.size)
  }
}

// request拦截器
request.interceptors.request.use(
  (config) => {
    console.log('request拦截器', config)
    removePending(config)
    // 如果repeatRequest不配置，那么默认该请求就取消重复接口请求
    // !config.repeatRequest &&
    const rToken = addPending(config)
    const store = useUserInfoStore()

    // 如果登录了，有customerId，则请求携带customerId
    // Do something before request is sent
    // 2c0cc00e673b11ee8825215d6f17267a
    config.headers['COPILOT-TOKEN'] = store.frontToken
    config.headers['COPILOT-ADMIN-TOKEN'] = store.token
    config.headers['token'] = store.token
    config.headers[requestUniquekey] = rToken
    return config
  },
  (error) => {
    // Do something with request error
    console.log(error) // for debug
    Promise.reject(error)
  }
)

// response拦截器
request.interceptors.response.use(
  // response => response,
  /**
   * 下面的注释为通过response自定义code来标示请求状态，当code返回如下情况为权限有问题，登出并返回到登录页
   * 如通过xmlhttprequest 状态码标识 逻辑可写在下面error中
   */
  async (response) => {
    // 已完成请求的删除请求中数组

    removePending(response.config)

    const res = response.data
    //忽略业务错误则直接跳过
    if (response.config.headers?.[IGNORE_BUSINESS_ERROR]) {
      return response
    }

    // 处理异常的情况
    if (res.code !== '200' || !res.ok) {
      if (whiteList.includes(response.config.url as string)) {
        return Promise.reject(response)
      }
      if (res.code === '505') {
        const {
          data: { entity = [] }
        } = await apiUserTeamList()
        const userInfoStore = useUserInfoStore()
       
        const hasOtherTeam = !!entity.length
        Modal.confirm({
          title: ' ',
          content: `${res.message}，点击【确定】后，${
            hasOtherTeam ? '切换至其他团队' : '强制退出登录'
          }`,
          okText: '确定',
          cancelText: ' ',
          type: 'warning',
          closable: false,
          async onOk() {
            if (hasOtherTeam) {
              const { data } = await apiChangeUserTeam({ teamId: entity[0].id })
              if (data.code === '200') {
                const bus = useChatBus(() => {})
                message.success(data.message)
                await userInfoStore.setUserInfo()
                bus.emit('setMenuList')
                const menuStore = useMenuStore()
                if (menuStore.isInFront) {
                  location.pathname = '/chat/chatDefault'
                  return
                }
                location.pathname = '/chat/PersonalCenter'
              }
              return
            }
            userInfoStore
              .loginOut()
              .then(() => {
                // location.reload() // 为了重新实例化vue-router对象 避免bug
              })
              .finally(() => {
                location.pathname = '/'
              })
          }
        })
        return Promise.reject(new Error('error'))
      }
      message.error(res.message)
      // 403:非法的customerId; 50012:其他客户端登录了;  401:customerId 过期了;
      if (res.code === '403' || res.code === '50012' || res.code === '401') {
        // if ( true) {
        const store = useUserInfoStore()
        const modal = document.querySelector('.logout-modal')
        if(!modal) {
          Modal.confirm({
            title: '确定登出',
            content: '你已被登出，请重新登录',
            okText: '重新登录',
            cancelText: ' ',
            type: 'warning',
            class: 'logout-modal',
            onOk() {
              store
                .loginOut()
                .then(() => {
                  // location.reload() // 为了重新实例化vue-router对象 避免bug
                })
                .finally(() => {
                  location.pathname = '/'
                })
            }
          })
        }
      }
      // return Promise.reject(new Error('error'))

      return Promise.reject(new Error('error'))
    } else {
      // 默认只返回data，不返回状态码和message
      // 通过 meta 中的 responseAll 配置来取决后台是否返回所有数据(包括状态码，message和data)
      // const isbackAll = response.config.meta && response.config.meta.responseAll
      // if (isbackAll) {
      //   return response
      // } else {
      //   return response
      // }
      return response
    }
  },
  (error) => {
    error.config && removePending(error.config)
    console.log('err' + error) // for debug
    if (error.code !== 'ERR_CANCELED') {
      message.error(error.message)
    }
    return Promise.reject(error)
  }
)

export default request
